//-------------------------------------------------------------------------------------
//
// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows.
//
// Licensed under the BSD license, see LICENSE in JGE root for details.
// 
// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) <jhkhui@gmail.com>
// 
//-------------------------------------------------------------------------------------

#include <stdio.h>

#include <JGE.h>
#include <JRenderer.h>
#include <JLBFont.h>
#include <JSprite.h>
#include <JFileSystem.h>
#include <JResourceManager.h>
#include <JTTFont.h>
#include <JSoundSystem.h>

#include <hge\hgeparticle.h>
#include <hge\hgefont.h>

#include "GameApp.h"
#include "GameEngine.h"
#include "GameMenu.h"
#include "Resources.h"

#define STONE_FIELD_X (120)
#define STONE_FIELD_Y (16)

#define STONE_FIELD_WIDTH (240)
#define STONE_FIELD_HEIGHT (240)

#define STONE_WIDTH (60)
#define STONE_HEIGHT (60)

//-------------------------------------------------------------------------------------
// Constructor. Variables can be initialized here.
//
//-------------------------------------------------------------------------------------
GameApp::GameApp()
{
	m_pResourceManager = NULL;
	m_pFont = NULL;
	m_pSmallFont = NULL;
	m_pModeTileEffect = NULL;
	//m_pMovingParticleSys = NULL;
	mTimer = 0.0;
	m_menuOffset = -10;
	m_menuDirection = 1;
	CurrentGameMode = GM_Logo;
}


//-------------------------------------------------------------------------------------
// Destructor.
//
//-------------------------------------------------------------------------------------
GameApp::~GameApp()
{

}


//-------------------------------------------------------------------------------------
// This is the init callback function. You should load and create your in-game 
// resources here.
// 
//-------------------------------------------------------------------------------------
void GameApp::Create()
{
	Resources::Init();

	JRenderer* renderer = JRenderer::GetInstance();

	m_pResourceManager = new JResourceManager();
	m_pResourceManager->LoadResource("15puzzle.resource");	

	m_pFont = new JTTFont();
	m_pFont->Load("font.ttf", 34);

	m_pSmallFont = new JTTFont();
	m_pSmallFont->Load("font.ttf", 14);

	//m_pMovingParticleSys = new hgeParticleSystem("particle1.psi", m_pResourceManager->GetQuad("moving"));
	//m_pMovingParticleSys->Fire();

	for(int index = 0; index < Resources::Available.size(); index++)
	{
		selectLanguageMenu.MenuItems.push_back(Resources::Available[index].languageName);
	}

	JSoundSystem* sound = JSoundSystem::GetInstance();

	m_pModeTileEffect = sound->LoadSample("click.wav");

	GameEngine::NewGame();
}


//-------------------------------------------------------------------------------------
// This is the clean up callback function. You should delete all your in-game 
// resources, for example texture and quads, here.
// 
//-------------------------------------------------------------------------------------
void GameApp::Destroy()
{
	//SAFE_DELETE(m_pMovingParticleSys);
	SAFE_DELETE(m_pModeTileEffect);
	SAFE_DELETE(m_pSmallFont);
	SAFE_DELETE(m_pFont);
	SAFE_DELETE(m_pResourceManager);
}

void GameApp::ProcessMenuOffset()
{
	if(mTimer>0.02f)
	{
		m_menuOffset += m_menuDirection;
		mTimer = 0;
	}

	if(m_menuOffset>8)
		m_menuDirection = -1;
	else if(m_menuOffset<-8)
		m_menuDirection = 1;
}

//-------------------------------------------------------------------------------------
// This is the update callback function and is called at each update frame
// before rendering. You should update the game logic here.
//
//-------------------------------------------------------------------------------------
void GameApp::Update()
{
	JGE* engine = JGE::GetInstance();

	float dt = engine->GetDelta();		// Get time elapsed since last update.

	mTimer += dt;

	if(mTimer>100000)
		mTimer = 0;

	switch(CurrentGameMode)
	{
	case GM_Logo:
		if(mTimer>2)
			CurrentGameMode = GM_SelectLanguage;
		break;
	case GM_SelectLanguage:
		if (engine->GetButtonClick(PSP_CTRL_UP))	
		{
			selectLanguageMenu.SelectPrevElement();
			JSoundSystem::GetInstance()->PlaySample(m_pModeTileEffect);
			Resources::SetCurrentIndex(selectLanguageMenu.GetSelectedElementIndex());
		}
		else if (engine->GetButtonClick(PSP_CTRL_DOWN))	
		{
			selectLanguageMenu.SelectNextElement();
			JSoundSystem::GetInstance()->PlaySample(m_pModeTileEffect);
			Resources::SetCurrentIndex(selectLanguageMenu.GetSelectedElementIndex());
		}
		else if (engine->GetButtonClick(PSP_CTRL_CIRCLE) || 
			engine->GetButtonClick(PSP_CTRL_START) ||
			engine->GetButtonClick(PSP_CTRL_CROSS))	
		{
			Resources::SetCurrentIndex(selectLanguageMenu.GetSelectedElementIndex());

			mainMenu.MenuItems.push_back(Resources::GetCurrent().mainMenuNewGame);
			//mainMenu.MenuItems.push_back(Resources::GetCurrent().mainMenuRecords);
			mainMenu.MenuItems.push_back(Resources::GetCurrent().mainMenuAbout);

			pauseMenu.MenuItems.push_back(Resources::GetCurrent().pauseMenuContinue);
			pauseMenu.MenuItems.push_back(Resources::GetCurrent().pauseMenuRestart);
			//pauseMenu.MenuItems.push_back(Resources::GetCurrent().pauseMenuRecords);
			pauseMenu.MenuItems.push_back(Resources::GetCurrent().pauseMenuAbout);

			CurrentGameMode = GM_MainMenu;
		}

		ProcessMenuOffset();

		break;
	case GM_MainMenu:
		if (engine->GetButtonClick(PSP_CTRL_UP))	
		{
			mainMenu.SelectPrevElement();
			JSoundSystem::GetInstance()->PlaySample(m_pModeTileEffect);
		}
		else if (engine->GetButtonClick(PSP_CTRL_DOWN))	
		{
			mainMenu.SelectNextElement();
			JSoundSystem::GetInstance()->PlaySample(m_pModeTileEffect);
		}
		else if (engine->GetButtonClick(PSP_CTRL_CIRCLE) || 
			engine->GetButtonClick(PSP_CTRL_START) || 
			engine->GetButtonClick(PSP_CTRL_CROSS))	
		{
			switch(mainMenu.GetSelectedElementIndex())
			{
			case 0: // New Game
				GameEngine::NewGame();
				CurrentGameMode = GM_Game;
				break;
			case 1: // About
				PrevGameMode = CurrentGameMode;
				CurrentGameMode = GM_About;
				break;
			}
		}

		ProcessMenuOffset();

		break;
	case GM_Game:

		// Move Tiles
		//if(mTimer>0.0005)
		{
			bool bPlaySample = false;

			for(int index = 1; index<16; index++)
			{
				GameEngine::TileItem& currentTile = GameEngine::Tiles[index];

				if(currentTile.XMoveStep>0)
				{
					currentTile.XMoveStep--;

					if(currentTile.XMoveStep==0)
						bPlaySample = true;
				}
				else if(currentTile.XMoveStep<0)
				{
					currentTile.XMoveStep++;

					if(currentTile.XMoveStep==0)
						bPlaySample = true;
				}

				if(currentTile.YMoveStep>0)
				{
					currentTile.YMoveStep--;

					if(currentTile.YMoveStep==0)
						bPlaySample = true;
				}
				else if(currentTile.YMoveStep<0)
				{
					currentTile.YMoveStep++;

					if(currentTile.YMoveStep==0)
						bPlaySample = true;
				}
			}

			if(bPlaySample)
				JSoundSystem::GetInstance()->PlaySample(m_pModeTileEffect);

			mTimer = 0;
		}
	
		// Process Button Logic
		if(GameEngine::IsUserWin())
		{
			CurrentGameMode = GM_Win;
		}
		else if (engine->GetButtonClick(PSP_CTRL_LEFT))	
		{
			GameEngine::MoveRightTile();
		}
		else if (engine->GetButtonClick(PSP_CTRL_RIGHT))	
		{
			GameEngine::MoveLeftTile();
		}
		else if (engine->GetButtonClick(PSP_CTRL_UP))	
		{
			GameEngine::MoveDownTile();
		}
		else if (engine->GetButtonClick(PSP_CTRL_DOWN))	
		{
			GameEngine::MoveUpTile();
		}
		else if (engine->GetButtonClick(PSP_CTRL_START) || 
			engine->GetButtonClick(PSP_CTRL_CROSS) || 
			engine->GetButtonClick(PSP_CTRL_CIRCLE))	
		{
			CurrentGameMode = GM_Pause;
			GameEngine::Pause();
			// TODO: Stop Game Engine Timer
		}
		break;
	case GM_Pause:
		if (engine->GetButtonClick(PSP_CTRL_UP))	
		{
			pauseMenu.SelectPrevElement();
			JSoundSystem::GetInstance()->PlaySample(m_pModeTileEffect);
		}
		else if (engine->GetButtonClick(PSP_CTRL_DOWN))	
		{
			pauseMenu.SelectNextElement();
			JSoundSystem::GetInstance()->PlaySample(m_pModeTileEffect);
		}
		else if (engine->GetButtonClick(PSP_CTRL_CIRCLE) || engine->GetButtonClick(PSP_CTRL_START) || engine->GetButtonClick(PSP_CTRL_CROSS))	
		{
			switch(pauseMenu.GetSelectedElementIndex())
			{
			case 0: // Continue
				CurrentGameMode = GM_Game;
				GameEngine::Resume();
				// TODO: Resume Game Engine Timer
				break;
			case 1: // Restart
				GameEngine::NewGame();
				CurrentGameMode = GM_Game;
				// TODO: Resume Game Engine Timer
				break;
			case 2: // About
				PrevGameMode = CurrentGameMode;
				CurrentGameMode = GM_About;
				break;
			}
		}

		ProcessMenuOffset();
		break;
	case GM_Win:
		if (engine->GetButtonClick(PSP_CTRL_CIRCLE) || engine->GetButtonClick(PSP_CTRL_START))	
		{
			CurrentGameMode = GM_Game;
			GameEngine::NewGame();
		}
		else if (engine->GetButtonClick(PSP_CTRL_CROSS))	
		{
			CurrentGameMode = GM_MainMenu;
		}

		break;
	case GM_About:
		if (engine->GetButtonClick(PSP_CTRL_CIRCLE) || engine->GetButtonClick(PSP_CTRL_CROSS))	
		{
			CurrentGameMode = PrevGameMode;
		}
		break;
	}
}


//-------------------------------------------------------------------------------------
// All rendering operations should be done in Render() only.
// 
//-------------------------------------------------------------------------------------
void GameApp::Render()
{
	switch(CurrentGameMode)
	{
	case GM_Logo:
		RenderLogo();
		break;
	case GM_SelectLanguage:
		RenderMenu(selectLanguageMenu);
		break;
	case GM_MainMenu:
		RenderMenu(mainMenu);
		break;
	case GM_Game:
		RenderGameMode();
		break;
	case GM_Pause:
		RenderMenu(pauseMenu);
		break;
	case GM_Win:
		RenderWin();
		break;
	case GM_About:
		RenderAbout();
		break;
	}
}

void GameApp::RenderLogo()
{
	JRenderer* renderer = JRenderer::GetInstance();		

	JQuad* logo = m_pResourceManager->GetQuad("logo");
	renderer->RenderQuad(logo, 0, 0);
}

void GameApp::RenderSelectLanguage()
{
	JRenderer* renderer = JRenderer::GetInstance();	
}

void GameApp::RenderMenu(GameMenu& menu)
{
	JRenderer* renderer = JRenderer::GetInstance();		

	JQuad* background = m_pResourceManager->GetQuad("background");
	renderer->RenderQuad(background, 0, 0);

	// turn off bilinear filtering to render sharp text
	renderer->EnableTextureFilter(false);

	m_pSmallFont->SetColor(ARGB(255,232,183,15));
	m_pSmallFont->RenderString(Resources::GetCurrent().buttonSelect.c_str(), 140, 254, JGETEXT_LEFT);
	m_pSmallFont->RenderString(Resources::GetCurrent().buttonSelect.c_str(), 340, 254, JGETEXT_RIGHT);

	for(int index = 0; index< menu.MenuItems.size(); index ++)
	{
		int offset = ((index == menu.GetSelectedElementIndex())?m_menuOffset:0);

		if(index == menu.GetSelectedElementIndex())
			m_pFont->SetColor(ARGB(255,232,183,15));
		else
			m_pFont->SetColor(ARGB(128,232,183,15));

		m_pFont->RenderString(menu.MenuItems[index].c_str(), 240 + offset, 28 + index*40, JGETEXT_CENTER);
	}

	renderer->EnableTextureFilter(true);
}

void GameApp::RenderWin()
{
	JRenderer* renderer = JRenderer::GetInstance();		

	JQuad* background = m_pResourceManager->GetQuad("background");
	renderer->RenderQuad(background, 0, 0);

	// turn off bilinear filtering to render sharp text
	renderer->EnableTextureFilter(false);

	m_pSmallFont->SetColor(ARGB(255,232,183,15));
	m_pSmallFont->RenderString(Resources::GetCurrent().buttonMenu.c_str(), 140, 254, JGETEXT_LEFT);
	m_pSmallFont->RenderString(Resources::GetCurrent().buttonNewGame.c_str(), 340, 254, JGETEXT_RIGHT);

	m_pFont->SetColor(ARGB(255,232,183,15));

	int index = 0;
	for(; index<Resources::GetCurrent().congratulationStrings.size(); index++)
	{
		m_pFont->RenderString(Resources::GetCurrent().congratulationStrings[index].c_str(), 240, 28 + index*40, JGETEXT_CENTER);
	}

	char strTime[20];
	int elapsedSecounds = GameEngine::GetElapsedSeconds();

	TIXML_SNPRINTF(strTime, 20, "%02d:%02d", elapsedSecounds/60, elapsedSecounds%60);
	m_pFont->RenderString(strTime, 240, 28 + index*40, JGETEXT_CENTER);

	index++;

	TIXML_SNPRINTF(strTime, 20, "%d", GameEngine::GetMoveCount());
	m_pFont->RenderString(strTime, 240, 28 + index*40, JGETEXT_CENTER);

}



void GameApp::RenderAbout()
{
	JRenderer* renderer = JRenderer::GetInstance();		

	JQuad* background = m_pResourceManager->GetQuad("background");
	renderer->RenderQuad(background, 0, 0);

	// turn off bilinear filtering to render sharp text
	renderer->EnableTextureFilter(false);

	m_pSmallFont->SetColor(ARGB(255,232,183,15));
	m_pSmallFont->RenderString(Resources::GetCurrent().buttonExit.c_str(), 140, 254, JGETEXT_LEFT);
	m_pSmallFont->RenderString(Resources::GetCurrent().buttonExit.c_str(), 340, 254, JGETEXT_RIGHT);

	for(int index = 0; index< Resources::GetCurrent().aboutStrings.size(); index ++)
	{
		m_pSmallFont->RenderString(Resources::GetCurrent().aboutStrings[index].c_str(), 240, 28 + index*20, JGETEXT_CENTER);
	}
}

void GameApp::RenderGameMode()
{
	// get JRenderer instance
	JRenderer* renderer = JRenderer::GetInstance();		

	JQuad* background = m_pResourceManager->GetQuad("background");
	renderer->RenderQuad(background, 0, 0);

	// Render Tiles
	for(int index = 1; index<16; index++)
	{
		GameEngine::TileItem& currentTile = GameEngine::Tiles[index];

		JQuad* tile = m_pResourceManager->GetQuad(currentTile.JQuadName);

		renderer->RenderQuad(tile, 
			STONE_FIELD_X + currentTile.X * STONE_WIDTH - currentTile.XMoveStep, 
			STONE_FIELD_Y  + currentTile.Y * STONE_HEIGHT- currentTile.YMoveStep);
	}

	renderer->EnableTextureFilter(false);
	// Render Time
	m_pSmallFont->SetColor(ARGB(255,232,183,15));
	m_pSmallFont->RenderString(Resources::GetCurrent().buttonPause.c_str(), 140, 254, JGETEXT_LEFT);
	m_pSmallFont->RenderString(Resources::GetCurrent().buttonPause.c_str(), 340, 254, JGETEXT_RIGHT);

	char strTime[20];
	int elapsedSecounds = GameEngine::GetElapsedSeconds();

	TIXML_SNPRINTF(strTime, 20, "%02d:%02d", elapsedSecounds/60, elapsedSecounds%60);
	m_pFont->SetColor(ARGB(255,232,183,15));
	m_pFont->RenderString(strTime, 380, 6);

	TIXML_SNPRINTF(strTime, 20, "%02d", GameEngine::GetMoveCount());
	m_pFont->SetColor(ARGB(255,232,183,15));
	m_pFont->RenderString(strTime, 380, 46);

	renderer->EnableTextureFilter(true);

	
}


//-------------------------------------------------------------------------------------
// This function is called when the system wants to pause the game. You can set a flag
// here to stop the update loop and audio playback.
//
//-------------------------------------------------------------------------------------
void GameApp::Pause()
{

}


//-------------------------------------------------------------------------------------
// This function is called when the game returns from the pause state.
//
//-------------------------------------------------------------------------------------
void GameApp::Resume()
{
}

